﻿#include "ending.h"


EndingMovie::EndingMovie()
{
	playing = 0;
	initialized = 0;
	buffering = 1;
}

EndingMovie::~EndingMovie()
{
	if (initialized)
	{
		buffering = 0;
		loader_thread.join();
	}
}

void EndingMovie::Load(CL_GraphicContext &gc, CL_ResourceManager &resources, CL_String name)
{
	CL_Resource res = resources.get_resource(name);
	mov_dir = resources.get_directory(res);
	CL_DomElement el = res.get_element();
	frame_prefix = el.get_attribute("frame_prefix");
	song = el.get_attribute("song");
	len = el.get_attribute_int("len");
	// Загрузить все кадры
	std::vector<CL_DomNode> frame_nodes = el.select_nodes("frame");
	current_frame = 0;
	n_frames = frame_nodes.size();
	for (size_t i = 0; i < n_frames; i++)
	{
		CL_DomElement frame = frame_nodes[i].to_element();
		_times.push_back(frame.get_attribute_int("time"));
		_frames.push_back(CL_StringHelp::text_to_int(frame.get_text()));
	}
	// загрузить текстуры всех первых кадров в буфер
	for ( int c = 0; c < 32; c++)
	{
		_tex_indexes[c] = _frames[c];
		_textures[c] = CL_Texture(gc, cl_texture_2d);
		_textures[c].set_image(CL_ImageProviderFactory::load(frame_prefix + CL_StringHelp::int_to_text(_frames[c]) +".png", mov_dir));
		cl_log_event("Debug", "Loaded frame %1", _tex_indexes[c]);
	}
	// Поставить индекс следующей подгружаемой текстуры
	next_tex = 0;
	// Запустить подгрузчик буфера
	loader_thread.start(this, &EndingMovie::fill_buffer);
	initialized = 1;
}

void EndingMovie::Start()
{
	if (!playing)
	{
		smanager.PlayMusic(song);
		playing = 1;
		current_frame = 0;
	}
}

void EndingMovie::Stop()
{
	smanager.StopMusic();
	playing = 0;
}

void EndingMovie::Update()
{
	if (playing && current_frame < n_frames)
	{
		int current_pos = smanager.GetMusicPosition();
		while ((current_frame + 1) < n_frames)
		{
			if (_times[current_frame+1] < current_pos)
			{
				load_mutex.lock();
				current_frame++;
				load_mutex.unlock();
			}
			else
				return;
		}
	}
}

void EndingMovie::draw(CL_GraphicContext &gc, float x, float y)
{
	int index = 33;
	load_mutex.lock();
	for ( int i = 0; i < 32; i++)
	{
		if (_tex_indexes[i] == _frames[current_frame])
		{
			index = i;
			break;
		}
	}
	if (index < 33)
		CL_Draw::texture(gc, _textures[index], CL_Rectf(x, y, x + 480, y + 290));
	load_mutex.unlock();
}

// Подгрузчик буфера
void EndingMovie::fill_buffer()
{
	// Непрерывно подгружать следующие кадры взамен использованных
	while (buffering)
	{
		int old_frame = _tex_indexes[next_tex];
		// Проверить, есть ли ещё этот кадр в очереди
		load_mutex.lock();
		int cur_frame = current_frame;
		load_mutex.unlock();
		int need_load = 1;
		int offset = 0;
		while (offset < 32 && (cur_frame + offset) < n_frames)
		{
			if (_frames[cur_frame + offset] == old_frame)
			{
				// кадр всё ещё используется
				need_load = 0;
				break;
			}
			offset++;
		}
		if ((cur_frame + offset) == n_frames)
		{
			// достигли конца фильма, больше ничего подгружать не надо
			need_load = 0;
			buffering = 0;
		}
		// Подгрузка нового кадра
		if (need_load)
		{
			int next_pos = cur_frame + 1;
			while (next_pos < n_frames)
			{
				need_load = 1;
				for (int i=0; i<32; i++)
					if (_tex_indexes[i] == _frames[next_pos])
					{
						need_load = 0;
						break;
					}
				if (need_load)
					break;
				else
					next_pos++;
			}
			if (need_load)
			{
				// определились с тем, что нужно загружать
				load_mutex.lock();
				_tex_indexes[next_tex] = _frames[next_pos];
				_textures[next_tex].set_image(CL_ImageProviderFactory::load(frame_prefix + CL_StringHelp::int_to_text(_frames[next_pos]) +".png", mov_dir));
				cl_log_event("Debug", "Loaded frame %1", _tex_indexes[next_tex]);
				next_tex = (next_tex + 1) % 32;
				load_mutex.unlock();
			}
		}
		else
		{
			CL_System::sleep(100);
		}
	}
}
